Aprenda Go em 10 minutos
Go (também conhecido como Golang) é uma linguagem de programação compilada e estaticamente tipada desenvolvida no Google. É conhecida por sua simplicidade, eficiência e excelente suporte para concorrência. Este tutorial vai ajudar você a aprender programação em Go rapidamente.
1. Escrevendo Seu Primeiro Programa em Go
Vamos começar com um programa simples. Crie um arquivo chamado hello.go
e insira o seguinte código:
package main
import "fmt"
func main() {
fmt.Println("Olá, Mundo!")
}
Salve o arquivo e execute o seguinte comando no terminal:
go run hello.go
A saída será:
Olá, Mundo!
Este programa simples demonstra a estrutura básica do Go:
package main
declara o nome do pacoteimport "fmt"
importa o pacote de formatação para operações de E/Sfunc main()
é o ponto de entrada do programafmt.Println()
imprime texto no console
2. Sintaxe Básica
Go tem uma sintaxe limpa e simples. Diferente do Python, Go usa chaves {}
para definir blocos de código e requer ponto e vírgula no final das instruções (embora geralmente sejam inseridos automaticamente).
// Este é um comentário de linha única
fmt.Println("Olá, Mundo!")
/*
Este é um comentário de múltiplas linhas
que abrange várias linhas
*/
Regras básicas de sintaxe em Go:
- Blocos de Código: Definidos por chaves
{}
- Comentários: Comentários de linha única começam com
//
, de múltiplas linhas com/* */
- Instruções: Terminam com ponto e vírgula (inseridos automaticamente)
- Declaração de Pacote: Todo arquivo começa com uma declaração de pacote
3. Variáveis e Tipos de Dados
Go é estaticamente tipada, o que significa que você deve declarar os tipos das variáveis. No entanto, Go suporta inferência de tipos com o operador :=
.
Métodos de declaração de variáveis:
// Declaração de tipo explícita
var nome string = "João"
var idade int = 25
// Inferência de tipo
nome := "João"
idade := 25
// Declaração múltipla de variáveis
var x, y int = 10, 20
x, y := 10, 20
Principais tipos de dados básicos do Go:
- Tipos inteiros:
int
,int8
,int16
,int32
,int64
,uint
,uint8
,uint16
,uint32
,uint64
,uintptr
- Tipos float:
float32
,float64
- String:
string
- Booleano:
bool
- Tipos complexos:
complex64
,complex128
3.1 Tipos Numéricos
Go fornece vários tipos numéricos para diferentes casos de uso:
// Tipos inteiros
var idade int = 25
var numeroPequeno int8 = 127
var numeroGrande int64 = 9223372036854775807
// Tipos float
var temperatura float32 = 36.5
var pi float64 = 3.14159265359
// Números complexos
var numeroComplexo complex64 = 3 + 4i
3.2 Tipo String
Strings em Go são sequências de bytes e são imutáveis:
// Declaração de string
var saudacao string = "Olá, Go!"
nome := "Alice"
// Operações com strings
fmt.Println(len(saudacao)) // Comprimento da string
fmt.Println(saudacao[0]) // Acessa primeiro caractere (byte)
fmt.Println(saudacao[0:5]) // Fatiamento de string
fmt.Println(strings.ToUpper(nome)) // Converte para maiúsculas
3.3 Tipo Booleano
O tipo booleano tem dois valores: true
e false
:
var estaAtivo bool = true
var estaCompleto bool = false
// Operações booleanas
resultado1 := true && false // false
resultado2 := true || false // true
resultado3 := !true // false
4. Constantes
Constantes são declaradas usando a palavra-chave const
e não podem ser alteradas:
const Pi = 3.14159
const MaxUsuarios = 1000
// Múltiplas constantes
const (
StatusOK = 200
StatusNaoEncontrado = 404
StatusErro = 500
)
// Constantes tipadas
const Versao string = "1.0.0"
5. Estruturas de Dados
Go fornece várias estruturas de dados integradas para armazenar e manipular dados.
5.1 Arrays
Arrays são sequências de tamanho fixo de elementos do mesmo tipo:
// Declaração de array
var numeros [5]int = [5]int{1, 2, 3, 4, 5}
nomes := [3]string{"Alice", "Bob", "Charlie"}
// Acessando elementos
fmt.Println(numeros[0]) // 1
numeros[0] = 10 // Modifica elemento
// Comprimento do array
fmt.Println(len(numeros)) // 5
5.2 Slices
Slices são arrays dinâmicos que podem crescer e diminuir:
// Declaração de slice
numeros := []int{1, 2, 3, 4, 5}
var sliceVazio []int
// Criando slices a partir de arrays
arr := [5]int{1, 2, 3, 4, 5}
slice := arr[1:4] // [2, 3, 4]
// Operações com slices
numeros = append(numeros, 6) // Adiciona elemento
numeros = append(numeros, 7, 8, 9) // Adiciona múltiplos elementos
// Capacidade e comprimento do slice
fmt.Println(len(numeros)) // Comprimento: 9
fmt.Println(cap(numeros)) // Capacidade: 10 (pode variar)
5.3 Maps
Maps são coleções não ordenadas de pares chave-valor:
// Declaração de map
estudante := map[string]interface{}{
"nome": "João",
"idade": 20,
"curso": "Ciência da Computação",
}
// Declaração alternativa
var notas map[string]int = make(map[string]int)
notas["matematica"] = 95
notas["ciencias"] = 88
// Acessando e modificando
fmt.Println(estudante["nome"])
estudante["idade"] = 21
estudante["media"] = 3.8
// Acesso seguro
if telefone, existe := estudante["telefone"]; existe {
fmt.Println(telefone)
} else {
fmt.Println("Telefone não fornecido")
}
// Iterando sobre o map
for chave, valor := range estudante {
fmt.Printf("%s: %v\n", chave, valor)
}
5.4 Structs
Structs são coleções de campos que podem ter tipos diferentes:
// Definição de struct
type Pessoa struct {
Nome string
Idade int
Cidade string
}
// Criando instâncias de struct
pessoa1 := Pessoa{"Alice", 25, "Nova York"}
pessoa2 := Pessoa{
Nome: "Bob",
Idade: 30,
Cidade: "Londres",
}
// Acessando campos
fmt.Println(pessoa1.Nome)
pessoa1.Idade = 26
6. Operações e Operadores
Go fornece um conjunto rico de operadores para vários cálculos e comparações.
- Operadores Aritméticos:
+
,-
,*
,/
,%
(módulo) - Operadores de Comparação:
==
,!=
,>
,<
,>=
,<=
- Operadores Lógicos:
&&
,||
,!
- Operadores Bitwise:
&
,|
,^
,<<
,>>
- Operadores de Atribuição:
=
,+=
,-=
,*=
,/=
6.1 Operadores Aritméticos
a, b := 10, 3
fmt.Printf("Adição: %d\n", a + b) // 13
fmt.Printf("Subtração: %d\n", a - b) // 7
fmt.Printf("Multiplicação: %d\n", a * b) // 30
fmt.Printf("Divisão: %d\n", a / b) // 3
fmt.Printf("Módulo: %d\n", a % b) // 1
6.2 Operadores de Comparação
x, y := 5, 10
fmt.Printf("Igual: %t\n", x == y) // false
fmt.Printf("Diferente: %t\n", x != y) // true
fmt.Printf("Maior que: %t\n", x > y) // false
fmt.Printf("Menor que: %t\n", x < y) // true
6.3 Operadores Lógicos
a, b := true, false
fmt.Printf("Operação AND: %t\n", a && b) // false
fmt.Printf("Operação OR: %t\n", a || b) // true
fmt.Printf("Operação NOT: %t\n", !a) // false
7. Controle de Fluxo
Go fornece várias instruções de controle de fluxo para gerenciar a execução do programa.
7.1 Instruções if
idade := 20
if idade >= 18 {
fmt.Println("Adulto")
} else if idade >= 13 {
fmt.Println("Adolescente")
} else {
fmt.Println("Criança")
}
// if com instrução curta
if nota := 85; nota >= 90 {
fmt.Println("Nota: A")
} else if nota >= 80 {
fmt.Println("Nota: B")
} else {
fmt.Println("Nota: C")
}
7.2 Loops for
Go tem apenas um construto de loop: for
// Loop for básico
for i := 0; i < 5; i++ {
fmt.Println(i)
}
// Loop estilo while
contador := 0
for contador < 5 {
fmt.Println(contador)
contador++
}
// Loop infinito
for {
fmt.Println("Isso vai executar para sempre")
break // Use break para sair
}
// Loop range (para slices, arrays, maps)
frutas := []string{"maçã", "banana", "cereja"}
for indice, fruta := range frutas {
fmt.Printf("%d: %s\n", indice, fruta)
}
7.3 Instruções switch
dia := "Segunda-feira"
switch dia {
case "Segunda-feira":
fmt.Println("Início da semana")
case "Sexta-feira":
fmt.Println("Fim de semana está próximo")
case "Sábado", "Domingo":
fmt.Println("Fim de semana!")
default:
fmt.Println("Dia comum")
}
// Switch sem expressão
nota := 85
switch {
case nota >= 90:
fmt.Println("Nota: A")
case nota >= 80:
fmt.Println("Nota: B")
case nota >= 70:
fmt.Println("Nota: C")
default:
fmt.Println("Nota: F")
}
8. Funções
Funções em Go são cidadãos de primeira classe e suportam múltiplos valores de retorno.
8.1 Funções Básicas
func cumprimentar(nome string) string {
return "Olá, " + nome + "!"
}
// Chamando a função
mensagem := cumprimentar("João")
fmt.Println(mensagem)
8.2 Múltiplos Valores de Retorno
func dividir(a, b float64) (float64, error) {
if b == 0 {
return 0, fmt.Errorf("não é possível dividir por zero")
}
return a / b, nil
}
// Usando múltiplos valores de retorno
resultado, err := dividir(10, 2)
if err != nil {
fmt.Println("Erro:", err)
} else {
fmt.Println("Resultado:", resultado)
}
8.3 Valores de Retorno Nomeados
func calcularRetangulo(largura, altura float64) (area float64, perimetro float64) {
area = largura * altura
perimetro = 2 * (largura + altura)
return // retorno nu
}
area, perimetro := calcularRetangulo(5, 3)
fmt.Printf("Área: %.2f, Perímetro: %.2f\n", area, perimetro)
8.4 Funções Variádicas
func somar(numeros ...int) int {
total := 0
for _, num := range numeros {
total += num
}
return total
}
fmt.Println(somar(1, 2, 3, 4)) // 10
fmt.Println(somar(5, 10, 15)) // 30
9. Ponteiros
Go tem ponteiros mas com sintaxe mais simples que C/C++:
func modificarValor(x *int) {
*x = *x * 2
}
func main() {
valor := 10
fmt.Println("Antes:", valor) // 10
modificarValor(&valor)
fmt.Println("Depois:", valor) // 20
}
10. Métodos
Métodos são funções com um argumento receptor:
type Retangulo struct {
Largura float64
Altura float64
}
// Método com receptor de valor
func (r Retangulo) Area() float64 {
return r.Largura * r.Altura
}
// Método com receptor de ponteiro
func (r *Retangulo) Escalar(fator float64) {
r.Largura *= fator
r.Altura *= fator
}
retangulo := Retangulo{Largura: 5, Altura: 3}
fmt.Println("Área:", retangulo.Area()) // 15
retangulo.Escalar(2)
fmt.Println("Área Escalada:", retangulo.Area()) // 60
11. Interfaces
Interfaces definem assinaturas de métodos que tipos podem implementar:
type Forma interface {
Area() float64
Perimetro() float64
}
type Circulo struct {
Raio float64
}
func (c Circulo) Area() float64 {
return 3.14159 * c.Raio * c.Raio
}
func (c Circulo) Perimetro() float64 {
return 2 * 3.14159 * c.Raio
}
func imprimirInfoForma(s Forma) {
fmt.Printf("Área: %.2f, Perímetro: %.2f\n", s.Area(), s.Perimetro())
}
circulo := Circulo{Raio: 5}
imprimirInfoForma(circulo)
12. Tratamento de Erros
Go usa tratamento de erros explícito em vez de exceções:
func lerArquivo(nomeArquivo string) (string, error) {
dados, err := os.ReadFile(nomeArquivo)
if err != nil {
return "", fmt.Errorf("falha ao ler arquivo %s: %w", nomeArquivo, err)
}
return string(dados), nil
}
conteudo, err := lerArquivo("exemplo.txt")
if err != nil {
fmt.Println("Erro:", err)
return
}
fmt.Println("Conteúdo:", conteudo)
13. Concorrência com Goroutines
Goroutines são threads leves gerenciadas pelo runtime do Go:
func trabalhador(id int) {
for i := 0; i < 3; i++ {
fmt.Printf("Trabalhador %d: %d\n", id, i)
time.Sleep(time.Millisecond * 100)
}
}
func main() {
// Inicia múltiplas goroutines
for i := 1; i <= 3; i++ {
go trabalhador(i)
}
// Aguarda as goroutines completarem
time.Sleep(time.Second)
fmt.Println("Todos os trabalhadores completaram")
}
14. Canais
Canais são usados para comunicação entre goroutines:
func produtor(ch chan<- int) {
for i := 0; i < 5; i++ {
ch <- i // Envia valor para o canal
time.Sleep(time.Millisecond * 100)
}
close(ch) // Fecha o canal quando terminar
}
func consumidor(ch <-chan int) {
for valor := range ch {
fmt.Println("Recebido:", valor)
}
}
func main() {
ch := make(chan int, 3) // Canal com buffer
go produtor(ch)
consumidor(ch)
fmt.Println("Comunicação por canal concluída")
}
15. Operações com Arquivos
Go fornece métodos simples para ler e escrever arquivos:
// Lendo arquivos
dados, err := os.ReadFile("exemplo.txt")
if err != nil {
fmt.Println("Erro lendo arquivo:", err)
return
}
fmt.Println("Conteúdo do arquivo:", string(dados))
// Escrevendo arquivos
conteudo := "Olá, Go!\n"
err = os.WriteFile("saida.txt", []byte(conteudo), 0644)
if err != nil {
fmt.Println("Erro escrevendo arquivo:", err)
return
}
fmt.Println("Arquivo escrito com sucesso")
16. Pacotes e Módulos
Módulos Go gerenciam dependências e versões de pacotes:
// Importando pacotes da biblioteca padrão
import (
"fmt"
"math"
"strings"
)
func main() {
fmt.Println(math.Sqrt(16)) // 4
fmt.Println(strings.ToUpper("go")) // GO
}
Para criar seu próprio pacote, crie um diretório com o nome do seu pacote e exporte funções capitalizando seus nomes.
17. Testes
Go tem suporte integrado para testes:
// No arquivo math_test.go
package main
import "testing"
func TestAdicionar(t *testing.T) {
resultado := adicionar(2, 3)
esperado := 5
if resultado != esperado {
t.Errorf("adicionar(2, 3) = %d; esperado %d", resultado, esperado)
}
}
func adicionar(a, b int) int {
return a + b
}
Execute os testes com: go test
18. Melhores Práticas
- Use
gofmt
para formatar seu código - Siga as convenções de nomenclatura do Go (camelCase para variáveis, PascalCase para exports)
- Trate erros explicitamente
- Use interfaces para abstração
- Prefira composição sobre herança
- Escreva testes abrangentes
- Use a biblioteca padrão sempre que possível
Este tutorial cobre os recursos essenciais da programação em Go. Com prática, você será capaz de construir aplicações eficientes e concorrentes usando os recursos poderosos do Go.